/* eslint-disable */
import { any, mask } from 'superstruct'
import axios from 'axios'
import ls from '@/lib/ls'
import { ApiError } from './utils'
import { ElNotification } from 'element-plus'
import useConfigStore from '@/store/config'
import { closeWebSocket } from '@/utils/websocket' 

const needTotalCount_api = ["MemberRechargeRecord", "MemberTransRecord", "MemberTransPointRecord", "GetStoreWineRecordList", "GetStoreWineList", "GetTakeWineRecordList", "GetRoomConsumeWineList", "GetTakeWineList", "GetClearOrder", "GetRoomOpeHistory",
    "GetOrderList","GetBusinessSetList", "GetPayOrderList", "GetSignRecordList", "GetReturnChangeGoodsRecord", "GetMountList", "GetMountRecordList", "GetGoodsList", "GetGoodsInfo", "GetMemberTicket", "GetWineRecoveryRecordList", "GetOrgTicketList", "GetShiftsRecordList",
    "GetDamageGoodsList", "GetMarketRoomDetailList", "GetMarketList","GetMarketGoodsDetailList","GetPointGoodDetailList","GetPointGoodList","GetSotreWineStat","GetRecoveryWineStat","GetSotreTakeWineStat","GetOrderPayRecord","GetBarTodayReport"
];

// 请求结果
class FetchResult {
    // 请求实例
    constructor(response) { 
        // 下载文件
        if (response.data instanceof Blob) {
            return response
        }
        let result = response.data
 
        let data = Object.prototype.hasOwnProperty.call(result, 'userInfo') ?
            result.userInfo :
            result.content?.objectList ? result.content.objectList[0].rowData : result.content;
        // console.log('result.content.objectList[0].rowData :>> ', result.content.objectList[0].rowData);
        if (Object.prototype.toString.call(data) === '[object String]') {
            try {
                data = JSON.parse(data)
            } catch (error) {
                // console.error(error)
            }
        }
        if (Object.prototype.toString.apply(data) !== '[object Object]') {
            data = {
                result: data
            }
        } 
         
        // 目前后端只返回opFlag为1和2，status为401，没了，将status状态码变成业务码
        result = new Object({
            code: response.status == 401 ? 401 : Number(result.opFlag),
            message: response.status == 401 ? response.statusText : result.opMsg,
            data
        }) 
        
        if(result.code === 401){
            result.data['__Code'] = result.code
            result.data['__Message'] = result.message
            return result.data
        }  

        // 某些接口返回的特殊数据进行构造
        const api = response.data.content ? response.data.content.objectList ? response.data.content.objectList[0].object : '' : '';
        if (needTotalCount_api.indexOf(api) !== -1) {
            result.data = {
                data: result.data.result,
                totalCount: response.data.content.objectList[0].totalCount
            } 
            if (result.data.data === undefined) {
                result.data.data = data 
            }
        } 
        Object.defineProperties(result.data , {
            __Code: {
                get() {
                    return result.code
                }
            },
            __Message: {
                get() {
                    return result.message
                }
            }
        })  
        return result.data
    }
}

// const baseURL = import.meta.env.MODE == 'development' ? '/api' : import.meta.env.VITE_BASE_API
const baseURL = import.meta.env.VITE_BASE_API

// 请求实例
const Fetch = axios.create({
    baseURL,
    //timeout: 5000,
    transformRequest: [
        function (data) {
            return JSON.stringify(data)
        }
    ],
    validateStatus: (status) => {
        return true
    }
})

// 拦截请求
Fetch.interceptors.request.use(
    (config) => {
        // Add X-Access-Token header to every request, you can add other custom headers here
        const token = ls.get('TOKEN')
        if (token) {
            config.headers.Authorization = `Bearer ${token}`
        }
        const USER_INFO = ls.get('USER_INFO')
        // console.log('config :>> ', config);
        // return
        if (config.data) {
            config.data.orgCode = USER_INFO ? USER_INFO.orgCode : ''
        }
        if (config.params) {
            config.params.orgCode = USER_INFO ? USER_INFO.orgCode : ''
        }
        return config
    },
    (error) => {
        Promise.reject(error)
    }
)

// 拦截请求结果
Fetch.interceptors.response.use(
    (response) => {
        return new FetchResult(response)
    },
    (error) => {
        return Promise.reject(error)
    }
)

// 下载目标
export const Download = function (uri, filename) {
    const downloadElement = document.createElement("a");
    const href = uri;
    if (filename) {
        downloadElement.download = filename;
    }
    downloadElement.style.display = "none";
    downloadElement.href = href;
    document.body.appendChild(downloadElement);
    downloadElement.click(); //点击下载
    document.body.removeChild(downloadElement); //下载完成移除元素
};

// 轮询
class LoopFetch {
    constructor(api, action, opts) {
        const options = Object.assign({
            // 请求间隔
            interval: 15e3,
            //
        }, opts)

        this.options = options
        this.action = action
        this.api = api
        this.timer = null;
        this.shouldStop = false;
        this.isStopped = false;

    }

    // 停止请求
    stop() {
        this.shouldStop = true;
        this.isStopped = true;
        clearTimeout(this.timer);
    }

    // 执行
    async exec() {
        const { interval } = this.options;
        if (this.shouldStop || this.isStopped) return;
        await this.action(this.api);
        if (!this.shouldStop && !this.isStopped) {
            this.timer = setTimeout(() => {
                this.exec();
            }, interval);
        }
    }
}

// 自定义请求类
export class Api {
    // 请求方法
    #method;
    // 请求地址
    #uri;
    // 初始地址
    #baseUri;
    constructor(uri, method) {
        this.#method = method
        this.#baseUri = uri
        this.#uri = uri
    }

    // 修改请求地址
    ReUri(func) {
        this.#uri = func(this.#baseUri)
        return this
    }

    // 发起请求
    async Do(...opt) {
        const resp = await this.Custom(...opt)
        // console.log('resp000 :>> ', resp);    
        // 接口返回成功
        if (resp.__Code === 1) { 
            return resp 
        } 
        // 目前__Message后端返回Unauthorized，前端临时先自行提示
        else if(resp.__Code === 401){ 
            const configStore = useConfigStore()
            closeWebSocket()  
            configStore.disconnect()    
            const err = new ApiError(resp.__Code, resp.__Message)
            ElNotification({
                title: '提示',
                message: 'token过期,请重新登录',
                type: 'error',
            })
            err.solve()
            ls.clear()
            throw err
        } 
        else{
            const err = new ApiError(resp.__Code, resp.__Message)  
            ElNotification({
                title: '错误',
                message: resp.__Message,
                type: 'error',
            }) 
            err.solve() 
            throw err
        }
    }

    // 发起请求 formData
    async FileDo(...opt) {
        const params = new FormData()
        const d = opt[0]
        if (Object.prototype.toString.call(d) === '[object Array]') {
            d.map(v => {
                params.append("file", v.file);
            })
        } else {
            params.append("file", d.file);
        }
        if (!opt[1]) {
            opt[1] = {}
        }
        if (!opt[1].headers) {
            opt[1].headers = {}
        }
        opt[1].headers = {
            'Content-Type': 'multipart/form-data'
        }
        opt[1].transformRequest = [
            function (data) {
                return data
            }
        ]
        opt[0] = params
        const resp = await this.Custom(...opt)
        // 接口返回成功
        if (resp.__Code === "1") {
            return resp
        } else {
            const err = new ApiError(resp.__Code, resp.__Message)
            err.prompt()
            throw err
        }
    }

    // 发起请求 不对结果拦截处理
    Custom(...opt) {
        return this.#method(this.#uri, ...opt)
    }

    // 轮询
    Loop(...opt) {
        return new LoopFetch(this, ...opt)
    }

    // 下载目标
    async Download(...opt) {
        const params = opt.length ? opt[0] : {}
        const resp = await this.#method(this.#uri, params, {
            responseType: "blob"
        })
        if (resp.data.type === "text/json") {
            const fetchText = await resp.data.text();
            const loadRes = JSON.parse(fetchText);
            const err = new ApiError(loadRes.code, loadRes.msg)
            err.solve()
            throw err
        } else {
            let filename = "";
            if (resp.headers.exportname) {
                filename = utf8.decode(resp.headers.exportname);
            }

            Download(URL.createObjectURL(resp.data), filename);
        }
    }
}

// get
export const Get = function (oUri, dataType = any(), options = {}) {
    return new Api(oUri, async (uri, getData, config = options) => {
        config.params = mask(getData, dataType)
        return await Fetch.get(uri, config)
    })
}

// post
export const Post = function (oUri, dataType = any(), options = { headers: { 'Content-Type': 'application/json;charset=utf-8' } }) {
    return new Api(oUri, async (uri, postData = {}, config = options) => {
        return await Fetch.post(uri, mask(postData, dataType), config)
    })
}

// patch
export const Patch = function (oUri, dataType = any(), options = { headers: { 'Content-Type': 'application/json;charset=utf-8' } }) {
    return new Api(oUri, async (uri, patchData = {}, config = options) => {
        return await Fetch.patch(uri, mask(patchData, dataType), config)
    })
}

// put
export const Put = function (oUri, dataType = any(), options = { headers: { 'Content-Type': 'application/json;charset=utf-8' } }) {
    return new Api(oUri, async (uri, putData = {}, config = options) => {
        return await Fetch.put(uri, mask(putData, dataType), config)
    })
}

// delete
export const Delete = function (oUri, dataType = any(), options = {}) {
    return new Api(oUri, async (uri, deleteData = {}, config = options) => {
        config.params = mask(deleteData, dataType)
        return await Fetch.delete(uri, config)
    })
}

// basis
export const Basis = axios.create({
    timeout: 5000,
    transformRequest: [
        function (data) {
            return JSON.stringify(data)
        }
    ]
})
export default Fetch;